#pragma once
#include "Common.h"
#include "NeroCore\NRtti.h"
#include "NeroEngine\NResource.h"
#include <hash_map>

namespace Graphics
{
	class Shader;
	class ShaderParameter;
	class Light;
	class RenderableEntity;
}

#ifdef DX_11
namespace Graphics
{
class Material : public Engine::NResource
{
	RTTI_DECLARATIONS(Material, Engine::NResource)
public:
	Material(const std::string& instanceName, const std::string& filePath);
	virtual ~Material(void);
	virtual void Initialize();
	virtual void SetShader(Shader* shader);
	virtual void Update(Graphics::RenderableEntity* entity);
	virtual void Render(Graphics::RenderableEntity* entity);

protected:
	virtual void BeginRender(){};
	virtual void EndRender(){};

protected:
	Graphics::Shader* mShader;
};
}
#elif defined( DX_9 )
namespace Graphics
{
class Material : public Engine::NResource
{
	RTTI_DECLARATIONS(Material, Engine::NResource)
public:
	typedef std::pair<std::string, ShaderParameter*> ParameterPair;
	typedef std::hash_map<std::string, ShaderParameter*> ParameterList;

public:
	Material(const std::string& instanceName, const std::string& filePath);
	virtual ~Material(void);
	virtual void Initialize();
	virtual void SetShader(Shader* shader);
	virtual void Update(Graphics::RenderableEntity* entity);
	virtual void Render(Graphics::RenderableEntity* entity);
	ShaderParameter* operator[](const char* parameterName);
	void SetParameter(ShaderParameter* effectParameter, void* value);	
	Graphics::Shader* GetShader(){return mShader;}	//fix this
	ParameterList Parameters(){return mParameters;}
	/*virtual void Update(Light* light) = 0;*/
protected:
	virtual void BeginRender(){};
	virtual void EndRender(){};

protected:
	Graphics::Shader* mShader;
	ParameterList mParameters;

#define MATERIAL_PARAM_DECLARATION(ParameterName)				\
	private:													\
		Graphics::ShaderParameter* m ## ParameterName;			\
	public:														\
		Graphics::ShaderParameter& ParameterName() const;

#define MATERIAL_PARAM_DEFINITION(Material, ParameterName)		\
	Graphics::ShaderParameter& Material::ParameterName() const	\
	{															\
		return *m ## ParameterName;								\
	}
#define MATERIAL_PARAM_INITIALIZATION(ParameterName) m ## ParameterName(NULL)


#define MATERIAL_PARAM_RETRIEVE(ParameterName)					\
	m ## ParameterName = (*this)[#ParameterName];				\
	assert(m ## ParameterName != NULL);	


};
}
#endif